namespace Microsoft.VisualStudio.EnterpriseTools.OperationDesigner
{
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.VirtualTreeGrid;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.Design;
    using System.Drawing;
    using System.Runtime.CompilerServices;
    using System.Windows.Forms;

    public class HeaderBranch : IServiceProvider, IBranch, IMultiColumnBranch, IOperationDesignerBranch
    {
        private ChildBranchInfo[] childBranchArray;
        private ColumnDescriptor[] columns;
        private List<ChildBranchInfo> currentBranches;

        private event BranchModificationEventHandler onBranchModification;

        public event BranchModificationEventHandler OnBranchModification
        {
            add
            {
                if (this.onBranchModification == null)
                {
                    this.AddEventHandlers();
                }
                this.onBranchModification = (BranchModificationEventHandler) Delegate.Combine(this.onBranchModification, value);
            }
            remove
            {
                this.onBranchModification = (BranchModificationEventHandler) Delegate.Remove(this.onBranchModification, value);
                if (this.onBranchModification == null)
                {
                    this.RemoveEventHandlers();
                }
            }
        }

        protected virtual void AddEventHandlers()
        {
            foreach (ColumnDescriptor descriptor in this.columns)
            {
                if (descriptor.ColumnIsCheckBox)
                {
                    foreach (ChildBranchInfo info in this.childBranchArray)
                    {
                        info.ChildModificationHandler = new BranchModificationEventHandler(this.OnChildBranchModification);
                    }
                }
            }
        }

        public VirtualTreeLabelEditData BeginLabelEdit(int row, int column, VirtualTreeLabelEditActivationStyles activationStyle)
        {
            throw new NotImplementedException();
        }

        public SubItemCellStyles ColumnStyles(int column)
        {
            return SubItemCellStyles.Simple;
        }

        public LabelEditResult CommitLabelEdit(int row, int column, string newText)
        {
            throw new NotImplementedException();
        }

        protected void DoBranchModification(BranchModificationEventArgs modification)
        {
            if (this.onBranchModification != null)
            {
                this.onBranchModification(this, modification);
            }
        }

        public void EndInsert(int row)
        {
        }

        protected virtual VirtualTreeAccessibilityData GetAccessibilityData(int row, int column)
        {
            if (column == 0)
            {
                return new VirtualTreeAccessibilityData("{1}, {3} {2}", OperationDesignerBranch.descriptionAccessibilityReplacementFields);
            }
            if (this.columns[column].ColumnIsCheckBox && (this.GetCheckBoxValue(row, column) != CheckBoxState.Unsupported))
            {
                return new VirtualTreeAccessibilityData("{0} {5} {3}", OperationDesignerBranch.descriptionAccessibilityReplacementFields);
            }
            return new VirtualTreeAccessibilityData("{3} {0}", OperationDesignerBranch.descriptionAccessibilityReplacementFields);
        }

        private CheckBoxState GetCheckBoxValue(int row, int column)
        {
            CheckBoxState unsupported = CheckBoxState.Unsupported;
            ColumnDescriptor descriptor = this.columns[column];
            OperationDesignerBranch branch = this.currentBranches[row].Branch as OperationDesignerBranch;
            if (branch != null)
            {
                for (int i = 0; i < branch.ElementCount; i++)
                {
                    object component = branch.GetElement(i);
                    CheckBoxState checkBoxValue = descriptor.GetCheckBoxValue(component);
                    if (unsupported == CheckBoxState.Unsupported)
                    {
                        unsupported = checkBoxValue;
                    }
                    else if (((unsupported == CheckBoxState.Checked) || (unsupported == CheckBoxState.Unchecked)) && ((unsupported != checkBoxValue) && (checkBoxValue != CheckBoxState.Unsupported)))
                    {
                        return CheckBoxState.Indeterminate;
                    }
                }
            }
            return unsupported;
        }

        public CommandID GetDefaultAction(int index)
        {
            return null;
        }

        protected virtual VirtualTreeDisplayData GetDisplayData(int row, int column, VirtualTreeDisplayDataMasks requiredData)
        {
            VirtualTreeDisplayData data = new VirtualTreeDisplayData(-1);
            if (column == 0)
            {
                data.ForeColor = SystemColors.ControlDarkDark;
                data.Bold = true;
            }
            if (((requiredData.Mask & VirtualTreeDisplayMasks.StateImage) != 0) && (row < this.currentBranches.Count))
            {
                ColumnDescriptor descriptor = this.columns[column];
                if (descriptor.ColumnIsCheckBox)
                {
                    CheckBoxState checkBoxValue = this.GetCheckBoxValue(row, column);
                    if (checkBoxValue != CheckBoxState.Unsupported)
                    {
                        data.StateImageIndex = (short) checkBoxValue;
                    }
                }
            }
            return data;
        }

        public int GetJaggedColumnCount(int row)
        {
            return this.columns.Length;
        }

        protected virtual object GetObject(int row, int column, ObjectStyle style)
        {
            switch (style)
            {
                case ObjectStyle.ExpandedBranch:
                    return this.currentBranches[row].Branch;

                case ObjectStyle.TrackingObject:
                    break;

                default:
                    if (style == OperationDesignerBranch.BrowsingObject)
                    {
                        break;
                    }
                    return null;
            }
            return this.currentBranches[row].Id;
        }

        public object GetObject(int row, int column, ObjectStyle style, ref int options)
        {
            return this.GetObject(row, column, style);
        }

        public object GetService(System.Type serviceType)
        {
            if ((this.columns.Length > 0) && (this.columns[0].Host != null))
            {
                return this.columns[0].Host.GetService(serviceType);
            }
            return null;
        }

        public string GetText(int row, int column)
        {
            if (column == 0)
            {
                return this.currentBranches[row].Name;
            }
            return string.Empty;
        }

        public string GetTipText(int row, int column, ToolTipType tipType)
        {
            return null;
        }

        public virtual OperationDesignerValueSupportedStates GetValueSupported(int row, int column)
        {
            ColumnDescriptor descriptor = this.columns[column];
            if (descriptor.ColumnIsCheckBox && (this.GetCheckBoxValue(row, column) != CheckBoxState.Unsupported))
            {
                return OperationDesignerValueSupportedStates.SupportsKeyboardNavigation;
            }
            return OperationDesignerValueSupportedStates.Default;
        }

        public void InsertCreatorNode(int index, int creatorNodeIndex)
        {
        }

        public bool IsExpandable(int row, int column)
        {
            return (column == 0);
        }

        public virtual LocateObjectData LocateObject(object obj, ObjectStyle style, int locateOptions)
        {
            int row = -1;
            int column = 0;
            int options = 0;
            switch (style)
            {
                case ObjectStyle.ExpandedBranch:
                case ObjectStyle.SubItemExpansion:
                    options = 0;
                    for (int i = 0; i < this.currentBranches.Count; i++)
                    {
                        if (this.currentBranches[i].Branch == obj)
                        {
                            return new LocateObjectData(i, 0, 1);
                        }
                    }
                    break;

                case ObjectStyle.TrackingObject:
                    for (int j = 0; j < this.currentBranches.Count; j++)
                    {
                        if ((obj != null) && (obj == this.currentBranches[j].Id))
                        {
                            return new LocateObjectData(j, 0, 1);
                        }
                        if (this.currentBranches[j].Branch.LocateObject(obj, ObjectStyle.TrackingObject, locateOptions).Options != 0)
                        {
                            return new LocateObjectData(j, 0, 2);
                        }
                    }
                    break;
            }
            return new LocateObjectData(row, column, options);
        }

        VirtualTreeAccessibilityData IBranch.GetAccessibilityData(int row, int column)
        {
            return this.GetAccessibilityData(row, column);
        }

        VirtualTreeDisplayData IBranch.GetDisplayData(int row, int column, VirtualTreeDisplayDataMasks requiredData)
        {
            return this.GetDisplayData(row, column, requiredData);
        }

        private void OnChildBranchModification(object sender, BranchModificationEventArgs e)
        {
            if ((e.Action == BranchModificationAction.DeleteItems) || (e.Action == BranchModificationAction.InsertItems))
            {
                for (int i = 0; i < this.childBranchArray.Length; i++)
                {
                    if ((this.childBranchArray[i].Branch == e.Branch) && (this.onBranchModification != null))
                    {
                        this.onBranchModification(this, BranchModificationEventArgs.DisplayDataChanged(new DisplayDataChangedData(VirtualTreeDisplayDataChanges.StateImage, this, i, -1, 1)));
                    }
                }
            }
        }

        public void OnDragEvent(object sender, int row, int column, DragEventType eventType, DragEventArgs args)
        {
        }

        public void OnGiveFeedback(GiveFeedbackEventArgs args, int row, int column)
        {
        }

        public void OnQueryContinueDrag(QueryContinueDragEventArgs args, int row, int column)
        {
        }

        public VirtualTreeStartDragData OnStartDrag(object sender, int row, int column, DragReason reason)
        {
            return VirtualTreeStartDragData.Empty;
        }

        public ProcessKeyResult ProcessKeyDown(int row, int column, KeyEventArgs e)
        {
            ProcessKeyResult result = new ProcessKeyResult(KeyAction.Process);
            Keys keyCode = e.KeyCode;
            if (keyCode != Keys.Tab)
            {
                switch (keyCode)
                {
                    case Keys.Up:
                        if (!e.Control)
                        {
                            result.Action = KeyAction.Handle;
                            result.Local = false;
                            result.Direction = NavigationDirection.Up;
                        }
                        return result;

                    case Keys.Right:
                        return result;

                    case Keys.Down:
                        if (!e.Control)
                        {
                            result.Action = KeyAction.Handle;
                            result.Local = false;
                            result.Direction = NavigationDirection.Down;
                        }
                        return result;

                    case Keys.Space:
                    {
                        if (this.columns[column].ColumnIsCheckBox)
                        {
                            return new ProcessKeyResult(KeyAction.Process);
                        }
                        int num = -1;
                        for (int i = 0; i < this.columns.Length; i++)
                        {
                            if (this.columns[i].ColumnIsCheckBox && (this.GetCheckBoxValue(row, i) != CheckBoxState.Unsupported))
                            {
                                if (num != -1)
                                {
                                    return new ProcessKeyResult(KeyAction.Process);
                                }
                                num = i;
                            }
                            if (num != -1)
                            {
                                this.ToggleState(row, num);
                                if (this.onBranchModification != null)
                                {
                                    this.onBranchModification(this, BranchModificationEventArgs.DisplayDataChanged(new DisplayDataChangedData(VirtualTreeDisplayDataChanges.StateImage, this, row, num, 1)));
                                    this.onBranchModification(this, BranchModificationEventArgs.DisplayDataChanged(new DisplayDataChangedData(VirtualTreeDisplayDataChanges.StateImage, this.childBranchArray[row].Branch, -1, num, -1)));
                                }
                                return new ProcessKeyResult(KeyAction.Discard);
                            }
                        }
                        return result;
                    }
                }
                return result;
            }
            result.Action = KeyAction.Handle;
            result.Direction = !e.Shift ? NavigationDirection.Right : NavigationDirection.Left;
            result.Local = false;
            return result;
        }

        public ProcessKeyResult ProcessKeyPress(int row, int column, char keyPressed, Keys modifiers)
        {
            return new ProcessKeyResult(KeyAction.Process);
        }

        protected virtual void RemoveEventHandlers()
        {
            foreach (ChildBranchInfo info in this.childBranchArray)
            {
                info.ChildModificationHandler = null;
            }
        }

        public void SetHeaderInfo(IList childBranchList, ColumnDescriptor[] columns)
        {
            if (childBranchList == null)
            {
                throw new ArgumentNullException("childBranchList");
            }
            this.childBranchArray = new ChildBranchInfo[childBranchList.Count];
            childBranchList.CopyTo(this.childBranchArray, 0);
            this.columns = columns;
            this.currentBranches = new List<ChildBranchInfo>(this.childBranchArray.Length);
            for (int i = 0; i < this.childBranchArray.Length; i++)
            {
                this.currentBranches.Add(this.childBranchArray[i]);
            }
        }

        public StateRefreshChanges SynchronizeState(int row, int column, IBranch matchBranch, int matchRow, int matchColumn)
        {
            return StateRefreshChanges.None;
        }

        public StateRefreshChanges ToggleState(int row, int column)
        {
            if ((row < 0) || (row >= this.currentBranches.Count))
            {
                throw new ArgumentException("row");
            }
            if ((column < 0) || (column >= this.columns.Length))
            {
                throw new ArgumentException("columns");
            }
            ColumnDescriptor descriptor = this.columns[column];
            if (descriptor.ColumnIsCheckBox)
            {
                try
                {
                    OperationDesignerBranch.InVirtualTreeEdit = true;
                    CheckBoxState checkBoxValue = this.GetCheckBoxValue(row, column);
                    if (checkBoxValue != CheckBoxState.Unsupported)
                    {
                        checkBoxValue = (checkBoxValue == CheckBoxState.Checked) ? CheckBoxState.Unchecked : CheckBoxState.Checked;
                        OperationDesignerBranch branch = this.currentBranches[row].Branch as OperationDesignerBranch;
                        if (branch != null)
                        {
                            Store store = null;
                            if (descriptor.Host != null)
                            {
                                store = descriptor.Host.Store;
                            }
                            if (store != null)
                            {
                                using (Transaction transaction = store.TransactionManager.BeginTransaction(descriptor.GetCheckBoxTransactionName(this.currentBranches[row].Id)))
                                {
                                    for (int i = 0; i < branch.ElementCount; i++)
                                    {
                                        object component = branch.GetElement(i);
                                        CheckBoxState state2 = descriptor.GetCheckBoxValue(component);
                                        if ((state2 != CheckBoxState.Unsupported) && (state2 != checkBoxValue))
                                        {
                                            descriptor.ToggleCheckBoxValue(component);
                                        }
                                    }
                                    transaction.Commit();
                                }
                                return StateRefreshChanges.Children;
                            }
                        }
                    }
                }
                finally
                {
                    OperationDesignerBranch.InVirtualTreeEdit = false;
                }
            }
            return StateRefreshChanges.None;
        }

        public int ColumnCount
        {
            get
            {
                return this.columns.Length;
            }
        }

        public BranchFeatures Features
        {
            get
            {
                return (BranchFeatures.StateChanges | BranchFeatures.InsertsAndDeletes | BranchFeatures.BranchRelocation | BranchFeatures.Expansions);
            }
        }

        public bool ReadOnly
        {
            get
            {
                return false;
            }
            set
            {
            }
        }

        public int UpdateCounter
        {
            get
            {
                return 0;
            }
        }

        public int VisibleItemCount
        {
            get
            {
                return this.currentBranches.Count;
            }
        }
    }
}

